﻿using System;
using System.Configuration;
using System.Web.Mvc;
using log4net;
using WikeSoft.Core.Exception;
using WikeSoft.Core.Extension;

namespace WikeSoft.Web
{
    /// <summary>
    /// 统一处理Mvc站点异常过滤器
    /// </summary>
    public class UnifyMvcSiteHandleErrorAttribute : HandleErrorAttribute
    {
        private static readonly ILog Log = LogManager.GetLogger("SystemError");
        public readonly string ModelErrorViewPage = "~/Views/Shared/ModelError.cshtml";

        /// <summary>
        /// 类型
        /// </summary>
        public MvcResultType MvcResultType { set; get; }

        /// <summary>
        /// 异常
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnException(ExceptionContext filterContext)
        {
            if (filterContext == null || filterContext.ExceptionHandled)
                return;

            if (!filterContext.Exception.IsTipException())
            {
                Log.Error(filterContext.Exception.Message, filterContext.Exception);
            }
            

            if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
            {
                HandleAjaxRequestError(filterContext);
            }
            else if (filterContext.Exception.IsTipException())
            {
                HandleRequestWithTipException(filterContext);
            }
            else
            {
                HandleRequestWithException(filterContext);
            }

            base.OnException(filterContext);
        }

        /// <summary>
        /// 处理Ajax请求产生的错误
        /// </summary>
        /// <param name="filterContext"></param>
        private void HandleAjaxRequestError(ExceptionContext filterContext)
        {
            var message = GetMessage(filterContext.Exception);

            filterContext.Result = BuildActionResultWithErrorMessage(filterContext, message);

            filterContext.HttpContext.Response.StatusCode = 200;
            filterContext.ExceptionHandled = true;
        }

        /// <summary>
        /// 构建包含错误信息的动作结果
        /// </summary>
        /// <param name="filterContext"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        private ActionResult BuildActionResultWithErrorMessage(ExceptionContext filterContext, string message)
        {
            var actionName = (string)filterContext.RouteData.Values["action"];

            if (MvcResultType == MvcResultType.PartialHtml || actionName.EndsWith("Partial"))
            {
                return new ContentResult { Content = message };
            }

            if (MvcResultType == MvcResultType.Modal)
            {
                return new PartialViewResult
                {
                    ViewName = ModelErrorViewPage,
                    ViewData = new ViewDataDictionary<string>(message)
                };
            }

            return new JsonResult()
            {
                Data = new { success = false, message },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }

        /// <summary>
        /// 获取提示信息
        /// </summary>
        /// <param name="exception"></param>
        /// <returns></returns>
        private string GetMessage(Exception exception)
        {
            if (exception.IsTipException())
            {
                return GetTipMessage(exception);
            }

            return ConfigurationManager.AppSettings["HideErrorToUser"] == "true"
                ? "Web内部异常，请联系系统管理员。"
                : exception.ToString();
        }

        /// <summary>
        /// 处理出现提示类异常的请求
        /// </summary>
        /// <param name="filterContext"></param>
        private void HandleRequestWithTipException(ExceptionContext filterContext)
        {
            var tipMessage = GetTipMessage(filterContext.Exception);

            filterContext.Result = new ViewResult()
            {
                ViewName = "Tip",
                MasterName = string.Empty,
                ViewData = new ViewDataDictionary<string>(tipMessage)
            };

            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 200;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }

        /// <summary>
        /// 处理出现提示类异常的请求
        /// </summary>
        /// <param name="filterContext"></param>
        private void HandleRequestWithException(ExceptionContext filterContext)
        {
            var tipMessage = filterContext.Exception.Message;

            filterContext.Result = new ViewResult()
            {
                ViewName = "Tip",
                MasterName = string.Empty,
                ViewData = new ViewDataDictionary<string>(tipMessage)
            };

            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }


        /// <summary>
        /// 获取提示消息
        /// </summary>
        /// <param name="exception"></param>
        /// <returns></returns>
        private string GetTipMessage(Exception exception)
        {
            if (exception is System.Web.HttpRequestValidationException)
            {
                return "请您输入合法字符。";
            }
            if (exception is TipInfoException)
            {
                return exception.Message;
            }
            return string.Empty;
        }
    }

    /// <summary>
    /// MVC动作结果类型
    /// </summary>
    public enum MvcResultType
    {
        /// <summary>
        /// 没有指定
        /// </summary>
        NotSpecify = 0,
        /// <summary>
        /// Html片段
        /// </summary>
        PartialHtml = 1,
        /// <summary>
        /// 弹出框
        /// </summary>
        Modal = 2
    }
}
